#include "DoomIIIMap.h"

using namespace libPortal::DoomIII;
using namespace boost;
using namespace std;
using namespace Eigen;

DoomIIIMap::DoomIIIMap()
{

}

DoomIIIMap::~DoomIIIMap()
{

}

DoomIIIMap::DoomIIIMap(const DoomIIIMap &other) :
  brushes(other.brushes)
{

}

DoomIIIMap& DoomIIIMap::operator=(const DoomIIIMap &rhs)
{
  if(&rhs==this)
    return *this;

  brushes = rhs.brushes;

  return *this;
}

bool DoomIIIMap::load(const std::string &filename)
{
  std::ifstream inputFile(filename.c_str(), std::ios::in);
  if(!inputFile.is_open())
    return false;

  char buffer[1000];
  float a,c,b,d,e,f,g,h,i,j;
  std::string line;

  DoomIIIBrush3D currentBrush;
  while(std::getline(inputFile, line))
    {
      if(sscanf(line.c_str(), " ( %f %f %f %f ) ( ( %f %f %f ) ( %f %f %f ) ) \"%s\"", 
		&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &buffer[0])==11)
	{
	  Hyperplane<double, 3> pEQ(Vector3d((double)a, (double)b, (double)c), (double)d);
	  shared_ptr<DoomIIIPlane> newPlane(new DoomIIIPlane(pEQ));
	  buffer[strlen(&buffer[0])-1] = 0; //hack to get rid of trailing quote
	  newPlane->textureFileName = &buffer[0];
	  newPlane->textureFileName.append(".tga");
	  //std::cout<<newPlane.textureFileName<<std::endl;
	  currentBrush.planes.clear();
	  newPlane->planeShape.setMaxQuad();
	  newPlane->texMat << e,f,g,
			      h,i,j,
			      0,0,1;
	  currentBrush.planes.push_back(newPlane);
	  while(std::getline(inputFile, line) &&
		sscanf(line.c_str(), " ( %f %f %f %f ) ( ( %f %f %f ) ( %f %f %f ) ) \"%s\"", 
		       &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &buffer[0])==11)
	    {
	      pEQ = Hyperplane<double, 3>(Vector3d((double)a, (double)b, (double)c), (double)d);
	      shared_ptr<DoomIIIPlane> anotherNewPlane(new DoomIIIPlane(pEQ));
	      buffer[strlen(&buffer[0])-1] = 0; //hack to get rid of trailing quote
	      anotherNewPlane->textureFileName = &buffer[0];
	      anotherNewPlane->textureFileName.append(".tga");
	      //std::cout<<anotherNewPlane.textureFileName<<std::endl;
	      anotherNewPlane->planeShape.setMaxQuad();
	      anotherNewPlane->texMat << e,f,g,
					 h,i,j,
					 0,0,1;
	      currentBrush.planes.push_back(anotherNewPlane);
	    }
	  brushes.push_back(currentBrush);
	}
    }

  inputFile.close();
  return true;
}

namespace libPortal
{
  namespace DoomIII
  {

    //Credit for the idea and structure of this code goes to the people at GtkRadiant
    //http://svn.icculus.org/twilight/trunk/hmap2/map.c?view=markup
    void computeTexCoords(DoomIIIPlane &p)
    {
      /*
      double vecs[2][4];
      double txvecs[2][4];
      double a, ac, as, bc, bs;
      a = -atan2(p.planeShape.normal[2], sqrt(p.planeShape.normal[0]*p.planeShape.normal[0]+p.planeShape.normal[1]*p.planeShape.normal[1]));
      ac = cos(a);
      as = sin(a);
      a = atan2(p.planeShape.normal[1], p.planeShape.normal[0]);
      bc = cos(a);
      bs = sin(a);
      vecs[0][0] = -bs;
      vecs[0][1] = bc;
      vecs[0][2] = 0;
      vecs[0][3] = 0; //not sure what this is
      vecs[1][0] = -as*bc;
      vecs[1][1] = -as*bs;
      vecs[1][2] = -ac;
      vecs[1][3] = 0; //not sure what this is
      txvecs[0][0] = p.texMat(0,0)*vecs[0][0]+p.texMat(0,1)*vecs[1][0];
      txvecs[0][1] = p.texMat(0,0)*vecs[0][1]+p.texMat(0,1)*vecs[1][1];
      txvecs[0][2] = p.texMat(0,0)*vecs[0][2]+p.texMat(0,1)*vecs[1][2];
      txvecs[0][3] = p.texMat(0,0)*vecs[0][3]+p.texMat(0,1)*vecs[1][3]+p.texMat(0, 2);
      txvecs[1][0] = p.texMat(1,0)*vecs[0][0]+p.texMat(1,1)*vecs[1][0];
      txvecs[1][1] = p.texMat(1,0)*vecs[0][1]+p.texMat(1,1)*vecs[1][1];
      txvecs[1][2] = p.texMat(1,0)*vecs[0][2]+p.texMat(1,1)*vecs[1][2];
      txvecs[1][3] = p.texMat(1,0)*vecs[0][3]+p.texMat(1,1)*vecs[1][3]+p.texMat(1, 2);
      Vector2d texcoord;
      Vector3d vert;
      p.texCoords.clear();
      p.texCoords.reserve(p.planeShape.numVerts());
      std::vector<Vector3d>::const_iterator iter, end;
      end = p.verts.end();
      for(iter=p.verts.begin();iter!=end;iter++) {
	vert = *iter;
	texcoord[0] = vert[0]*txvecs[0][0]+vert[1]*txvecs[0][1]+vert[2]*txvecs[0][2] + txvecs[0][3];
	texcoord[1] = vert[0]*txvecs[1][0]+vert[1]*txvecs[1][1]+vert[2]*txvecs[1][2] + txvecs[1][3];
	p.texCoords.push_back(texcoord);
      }
      */
    }
  }
}

double DoomIIIMap::mapSize() const
{
  /*
  double max = 1;
  BOOST_FOREACH(DoomIIIBrush3D b, brushes)
    {
      BOOST_FOREACH(shared_ptr<BSPPlane> p, b.planes)
	{
	  BOOST_FOREACH(Vector3d v, p->verts) {
	    if(v.norm()>max)
	      max = v.norm();
	  }
	}
    }
  return max;
  */
  return 0;
}

DoomIIIPlane::DoomIIIPlane(Hyperplane<double, 3> planeEquation) :
  BSPPlane(planeEquation)
{
  
}

std::vector<DoomIIIBrush3D>::const_iterator DoomIIIMap::begin() const
{
  return brushes.begin();
}

std::vector<DoomIIIBrush3D>::const_iterator DoomIIIMap::end() const
{
  return brushes.end();
}
